package model

import "fmt"

type Bank struct {
	// 各个资源名字
	Name []string
	// 可用资源
	Available []int
	// 各进程对资源的最大需求
	Max [][]int
	// 已分配的资源
	Allocation [][]int
	// 各进程还需要分配的资源
	Need [][]int
	// 进程此次申请的资源
	Request []int
	// 安全序列
	SequenceSafe []int
	// 进程的数量
	ProcessNums int
	// 资源种类的数量
	ResourceNums int
}

func NewBank(pro, res int, name []string, ava []int, all, max [][]int) *Bank {
	bank := &Bank{
		Name:         name,
		Available:    ava,
		Max:          max,
		Allocation:   all,
		Need:         nil,
		Request:      nil,
		SequenceSafe: nil,
		ProcessNums:  pro,
		ResourceNums: res,
	}
	bank.Need = make([][]int, pro)
	for i, _ := range bank.Need {
		bank.Need[i] = make([]int, res)
	}
	bank.Request = make([]int, res)
	bank.SequenceSafe = make([]int, pro)

	for i := 0; i < pro; i++ {
		for j := 0; j < res; j++ {
			bank.Need[i][j] = bank.Max[i][j] - bank.Allocation[i][j]
		}
	}
	for i := 0; i < pro; i++ {
		for j := 0; j < res; j++ {
			bank.Available[j] = bank.Available[j] - bank.Allocation[i][j]
		}
	}
	fmt.Println(bank.Available)
	return bank
}

func (b *Bank) Des() bool {
	work, fin := make([]int, b.ResourceNums), make([]bool, b.ProcessNums)
	num, index := 0, 0
	copy(work, b.Available)
	for i := 0; i < b.ProcessNums; i++ {
		// all allocate
		if num == b.ProcessNums {
			break
		}
		for j := 0; j < b.ProcessNums; j++ {
			if !fin[j] && compare(work, b.Need[j], b.ResourceNums) {
				fin[j] = true
				b.SequenceSafe[index] = j + 1
				index++
				num++
				for n := 0; n < b.ResourceNums; n++ {
					work[n] = work[n] + b.Allocation[j][n]
				}
			}
		}
	}
	for i := 0; i < b.ProcessNums; i++ {
		if !fin[i] {
			return false
		}
	}
	fmt.Println("SequenceSafe：", b.SequenceSafe)
	return true
}

func (b *Bank) ReDes(n int) {
	if compare(b.Available, b.Request, b.ResourceNums) && compare(b.Need[n], b.Request, b.ResourceNums) {
		for i := 0; i < b.ResourceNums; i++ {
			// allocate
			b.Allocation[n][i] = b.Allocation[n][i] + b.Request[i]
			b.Need[n][i] = b.Need[n][i] - b.Request[i]
			b.Available[i] = b.Available[i] - b.Request[i]
		}
		if b.Des() {
			fmt.Println("request safe")
		} else {
			fmt.Println(">>>>> request unsafe <<<<<")
			for i := 0; i < b.ResourceNums; i++ {
				// allocate
				b.Allocation[n][i] = b.Allocation[n][i] - b.Request[i]
				b.Need[n][i] = b.Need[n][i] + b.Request[i]
				b.Available[i] = b.Available[i] + b.Request[i]
			}
		}
	} else {
		fmt.Println("has not space for request of process", n)
	}
}

func compare(a, b []int, res int) bool {
	for i := 0; i < res; i++ {
		if a[i] < b[i] {
			return false
		}
	}
	return true
}

func (b *Bank) Show() {
	fmt.Println("Process ID       Max             All            Need")
	fmt.Println("               A  B  C         A  B  C        A  B  C")
	for i := 0; i < b.ProcessNums; i++ {
		fmt.Printf("%11d", i+1)
		for j := 0; j < b.ResourceNums; j++ {
			fmt.Printf("%4d", b.Max[i][j])
		}
		fmt.Printf("    ")
		for j := 0; j < b.ResourceNums; j++ {
			fmt.Printf("%4d", b.Allocation[i][j])
		}
		fmt.Printf("    ")
		for j := 0; j < b.ResourceNums; j++ {
			fmt.Printf("%4d", b.Need[i][j])
		}
		fmt.Println()
	}
}
